//
//  JWLandscapeManager.m
//  KotH
//
//  Created by James Weatherley on 05/08/2008.
//  Copyright 2008 James Weatherley. All rights reserved.
//

#import "../koth.h"

//static GLfloat sideColour[2][3] = {{0.54f, 0.33f, 0.27f}, {0.76f, 0.6f, 0.32f}};



@interface JWLandscapeManager (PrivateMethods)

-(void)drawInitialEdge:(int)z;
-(void)drawFinalEdge:(int)z;
-(void)drawRiserFromHeight:(int)height toSquare:(JWSquare*)square;
-(void)drawFillins:(int)z;
-(void)drawCubicFillins:(int)z;

@end



@implementation JWLandscapeManager

-(id)initWithEntity:(JWLandscape*)landscape_
{
	self = [super init];
	[self addEntity:landscape_];
	return self;
}

-(void)dealloc
{
	[self removeAllEntities];
	[super dealloc];
}

-(NSObject*)entity
{
	return landscape;
}

-(void)addEntity:(NSObject*)entity
{
	assert([entity class] == [JWLandscape class]);
	if(entity != landscape) {
				
		[landscape release];
		landscape = (JWLandscape*)entity;
		[landscape retain];
		
		pfglDestroyVertexArray(vertexArray);
		vertexArray = pfglCreateVertexArray();
		[self updateVertexArrays];
	}
}

-(void)removeEntity:(NSObject*)entity
{
	[landscape release];
	landscape = nil;
	
	pfglDestroyVertexArray(vertexArray);
	vertexArray = NULL;
}

-(void)removeAllEntities
{
	[self removeEntity:landscape];
}

-(void)updateVertexArrays
{
	int length = [landscape dimensions].height;
	int width = [landscape dimensions].width;
	GLfloat height = 0.0f;
	//NSArray* landscapeArray = [landscape landscape];
	JWLandscapeMode landscapeMode = [landscape landscapeMode];
	
	//glShadeModel(GL_FLAT);
	pfglBegin(GL_QUADS);
	// Draw in strips from back to front.
	for(int z = 0; z < width; ++z) {
		
		height = 0.0f;
		[self drawInitialEdge:z];

		// Now draw the squares. We're not using quad strips as we need to name
		// individual squares so that we can pick them.

		for(int x = 0; x < length; ++x) {
				
			JWSquare* square = [landscape getSquareAtX:x z:z];
			
			if([square height] != height) {
				// Only draw vertical risers if we're in cubic mode.
				if(landscapeMode == JWLandscapeCubic) {
					[self drawRiserFromHeight:height toSquare:square];
				}
				height = [square height];
			}
			//[self drawSquare:square];
			[square drawSelf];
		}
		// Finish off by drawing the end side...
		[self drawFinalEdge:z];

		// ...and fill in the gaps between strips.
		[self drawFillins:z];
	}
	//pfglEnd();
	pfglEndReturnVertexArray(vertexArray);
	
	//VertexArray* array = pfglCreateVertexArray();
	//pfglDrawVertexArray(array);
	//pfglDestroyVertexArray(array);
	
	//qglPushMatrix();
	//qglTranslatef(0.5f, 0.0f, 0.5f);
	
	//qglPopMatrix();
}

-(void)draw
{
	pfglDrawVertexArray(vertexArray);
	//[self fillVertexArray];
}

#pragma mark Private Methods
-(void)drawInitialEdge:(int)z
{
#if 1
	GLfloat height = 0.0f;
	GLfloat h2 = 0.0f;
	//NSArray* landscapeArray = [landscape landscape];
	JWLandscapeMode landscapeMode = [landscape landscapeMode];
	//int length = [landscape dimensions].height;
	int width = [landscape dimensions].width;
	
	//qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sideColour[0]);
	//glLoadName(JWLandscapeLeftSide);
	
	JWSquare* square = [landscape getSquareAtX:0 z:z];
	if([square height] != height) {
		height = [square height];
		h2 = height;
	}
	if(landscapeMode == JWLandscapeSmooth && z != width - 1) {
		h2 = [[landscape getSquareAtX:0 z:z + 1]  height];
	}

	//pfglBegin(GL_QUADS);
	{
		pfglColor4f(sideColour[0][0], sideColour[0][1], sideColour[0][2], 1.0f);
		pfglNormal3f(1.0f, 0.0f, 0.0f);
		pfglVertex3f(0.0f, 0.0f, z + 1.0f);
		pfglVertex3f(0.0f, h2, z + 1.0f);
		pfglVertex3f(0.0f, height, z);
		pfglVertex3f(0.0f, 0.0f, z);
	}
	//pfglEnd();
#endif
	//glLoadName(0);
}

-(void)drawFinalEdge:(int)z
{
#if 1
	GLfloat maxX = [landscape dimensions].height;
	GLfloat maxZ = [landscape dimensions].width;
	//NSArray* landscapeArray = [landscape landscape];
	JWLandscapeMode landscapeMode = [landscape landscapeMode];

	//qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sideColour[0]);
	//glLoadName(JWLandscapeRightSide);
	
	//GLfloat h1 = [[landscapeArray objectAtIndex:z * maxX + maxZ - 1] height];
	GLfloat h1 = [[landscape getSquareAtX:maxX - 1 z:z] height];
	
	GLfloat h2 = h1;
	if(landscapeMode == JWLandscapeSmooth && z != maxZ - 1) {
		//h2= [[landscapeArray objectAtIndex:(z + 1) * length + width - 1] height];
		h2 = [[landscape getSquareAtX:maxX - 1 z:z + 1] height];
	}
	
	//pfglBegin(GL_QUADS); 
	{
		pfglColor4f(sideColour[0][0], sideColour[0][1], sideColour[0][2], 1.0f);
		pfglNormal3f(1.0f, 0.0f, 0.0f);
		pfglVertex3f(maxX, h1, z);
		pfglVertex3f(maxX, h2, z + 1.0f);
		pfglVertex3f(maxX, 0.0f, z + 1.0f);
		pfglVertex3f(maxX, 0.0f, z);
	}
	//pfglEnd();
	//glLoadName(0);
#endif
}

-(void)drawRiserFromHeight:(int)height toSquare:(JWSquare*)square
{
#if 0
	int x = [square x];
	int z = [square z];
	
	qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sideColour[0]);
	//glLoadName(JWLandscapeRiser0);
	
	pfglBegin(GL_QUADS);
	{
		pfglVertex3f(x, height, z);
		pfglVertex3f(x, height, z + 1.0f);
		pfglVertex3f(x, [square height], z + 1.0f);
		pfglVertex3f(x, [square height], z);
	}
	pfglEnd();
	//glLoadName(0);
#endif
}


-(void)drawFillins:(int)z
{
#if 1
	qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sideColour[1]);
	JWLandscapeMode landscapeMode = [landscape landscapeMode];
	
	if(landscapeMode == JWLandscapeCubic) {
		[self drawCubicFillins:z];
	} else {
		// Non-cubic mode. In classic mode there are gaps between the strips. These are filled
		// with a quad strip. We joined the gaps up in smooth mode, so there is nothing to do
		// except draw the front and back sides. The sides are also drawn in classic mode.
		// Cubic mode drew its front and back sides when it drew its risers in the block above.
		int length = [landscape dimensions].height;
		int width = [landscape dimensions].width;
		//NSArray* landscapeArray = [landscape landscape];
		GLfloat h1, h2;
		
		//if(z == 0) {
			//glLoadName(JWLandscapeBackSide);
			//qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sideColour[1]);
		//} else {
			//glLoadName(QUAD_STRIP_OFFSET + z);
			//qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sideColour[1]);
		//}
		//pfglBegin(GL_QUADS);
		{
			if(z == 0) {
				h1 = 0.0f;
			} else {
				h1 = [[landscape getSquareAtX:0 z:z - 1] height];
			}
			

			float oldH1 = h1;
			//float oldH2 = [[landscapeArray objectAtIndex:z * length] height];
			float oldH2 = [[landscape getSquareAtX:0 z:z] height];
			
			for(int x = 0; x < length; ++x) {
				if(landscapeMode == JWLandscapeLaminar || z == 0) {
					if(z == 0) {
						h1 = 0.0f;
					} else {
						//h1 = [[landscapeArray objectAtIndex:(z - 1) * length + x] height];
						h1 = [[landscape getSquareAtX:x z:z - 1] height];
					}
					//h2 = [[landscapeArray objectAtIndex:z * length + x] height];
					h2 = [[landscape getSquareAtX:x z:z] height];
					pfglColor4f(sideColour[1][0], sideColour[1][1], sideColour[1][2], 1.0f);
					pfglNormal3f(0.0f, 0.0f, 1.0f);
					pfglVertex3f(x + 1.0f, h1, z);
					pfglVertex3f(x, oldH1, z);
					pfglVertex3f(x, oldH2, z);
					pfglVertex3f(x + 1.0f, h2, z);

					oldH1 = h1;
					oldH2 = h2;
				}
			}
		}
		//pfglEnd();
		//glLoadName(0);
		
		if(z == width - 1) {
			//glLoadName(JWLandscapeFrontSide);
			//qglMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sideColour[1]);
			
			//pfglBegin(GL_QUADS);
			{
				//float oldH1 = [[landscapeArray objectAtIndex:z * length] height];
				float oldH1 = [[landscape getSquareAtX:0 z:z] height];
				float oldH2 = 0.0f;
				
				for(int x = 0; x < length; ++x) {
					//h1 = [[landscapeArray objectAtIndex:z * length + x] height];
					h1 = [[landscape getSquareAtX:x z:z] height];
					h2 = 0.0f;
					pfglColor4f(sideColour[1][0], sideColour[1][1], sideColour[1][2], 1.0f);
					pfglNormal3f(0.0f, 0.0f, 1.0f);
					pfglVertex3f(x + 1.0f, h1, z + 1.0f);
					pfglVertex3f(x, oldH1, z + 1.0f);
					pfglVertex3f(x, oldH2, z + 1.0f);
					pfglVertex3f(x + 1.0f, h2, z + 1.0f);
					
					oldH1 = h1;
					oldH2 = h2;
				}
			}
			//pfglEnd();
			//glLoadName(0);
		}	
	}
#endif
}

-(void)drawCubicFillins:(int)z
{
#if 0
	int length = [landscape dimensions].height;
	int width = [landscape dimensions].width;
	NSArray* landscapeArray = [landscape landscape];
	GLfloat h1, h2;
	
	glLoadName(JWLandscapeRiser1);
	pfglBegin(GL_QUADS);
	{
		for(int x = 0; x < length; ++x) {
			
			if(z == 0) {
				h1 = 0.0f;
			} else {
				h1 = [[landscapeArray objectAtIndex:(z - 1) * length + x] height];
			}
			h2 = [[landscapeArray objectAtIndex:z * length + x] height];
			
			if(abs(h1 - h2) > JW_DEPS) {
				pfglVertex3f(x + 1.0f, h1, z);
				pfglVertex3f(x, h1, z);
				pfglVertex3f(x, h2, z);
				pfglVertex3f(x + 1.0f, h2, z);
			}
			
			if(z == width - 1) {
				h1 = [[landscapeArray objectAtIndex:z * length + x] height];
				h2 = 0.0f;
				if(abs(h1 - h2) > JW_DEPS) {
					pfglVertex3f(x + 1.0f, h1, z + 1.0f);
					pfglVertex3f(x, h1, z + 1.0f);
					pfglVertex3f(x, h2, z + 1.0f);
					pfglVertex3f(x + 1.0f, h2, z + 1.0f);
				}
			}
		}
	}
	pfglEnd();
#endif
}

-(void)postDraw
{
}

@end
